//
//  KDJ.cpp
//  Chart
//
//  Created by ma xiaoyang on 6/19/13.
//
//

#include "KDJ.h"
using namespace ytx;
using namespace std;

KDJ::KDJ(IndexConfig indexConfig):IndexData(indexConfig, 2)
{
    type = QuotationType::KDJ;
    indexName = "KDJ";
    lineData.assign(3, vector<double>());
    this->setRow(0);
}

KDJ::~KDJ()
{
    
}

double KDJ::getRSV(Quotation * data, int index, int n)
{
    vector<KLineItem> & item = data->kLineData;
    if (index <= n-1) {
        return 50;
    }
    double h = item[index].high;
    double l = item[index].low;
    for (int z = 0; z<n; z++) {
        h = MAX(item[index - z].high, h);
        l = MIN(item[index - z].low, l);
    }
    if (h == l) {
        return 50;
    }
    return (item[index].close - l) / (h-l) *100;
}

void KDJ::updateLastest(Quotation *data)
{
    double n = para.value[0];
    double m1 = para.value[1];
    double m2 = para.value[2];
    
    n = (int) Tools::between(para.range[0].first, para.range[0].second, n);
    m1 = (int) Tools::between(para.range[1].first, para.range[1].second, m1);
    m2 = (int) Tools::between(para.range[2].first, para.range[2].second, m2);
    
    if( !(data->getDataLength() < n) ){
        int i = (int)(data->kLineData.size()-1);
        
        double RSV = getRSV(data, i, n), K, D, J;
        
        K = computeSMA(RSV, lineData[0][i - 1], m1, 1);
        D = computeSMA(K, lineData[1][i - 1], m2, 1);
        J = 3 * K - 2* D;
//        J = Tools::between(0, 100, J);
        
        lineData[0].back() = K;
        lineData[1].back() = D;
        lineData[2].back() = J;
    }
}


void KDJ::calculate(Quotation * data){
    lineData.clear();
    
    double n = para.value[0];
    double m1 = para.value[1];
    double m2 = para.value[2];
    
    int i = 0, j = (int)data->kLineData.size();
    vector<double> H(j),L(j),K(j),D(j),J(j),RSV(j);
    
    n = (int) Tools::between(para.range[0].first, para.range[0].second, n);
    m1 = (int) Tools::between(para.range[1].first, para.range[1].second, m1);
    m2 = (int) Tools::between(para.range[2].first, para.range[2].second, m2);
    
    if (data->getDataLength() < n){
        return;
    }
    
    for(i = 0;i<2;i++)
    {
        K[i] = 50;
        D[i] = 50;
        J[i] = 50;
        RSV[i] = 50;
    }
    i = 1;
    while (i<j) {
        H[i-1] = data->kLineData[i].high;
        L[i-1] = data->kLineData[i].low;
        RSV[i] = getRSV(data, i, n);
        if (i==1)
            K[i] = computeSMA(RSV[i], RSV[i-1], m1 ,1);
        else if (i >1)
            K[i] = computeSMA(RSV[i],K[i-1], m1, 1);
        if (i ==2)
            D[i] = computeSMA(K[i], K[i-1], m2, 1);
        else if (i>2)
            D[i] = computeSMA(K[i], D[i-1], m2, 1);
        if (i>=2) {
            J[i] = 3 * K[i] - 2* D[i];
//            J[i] = J[i] > 100 ? 100 : J[i];
//            J[i] = J[i] < 0 ? 0 : J[i];
        }
        i++;
    }
    
    lineData.push_back(K);
    lineData.push_back(D);
    lineData.push_back(J);
}

string KDJ::getCrosshairYData(int index)
{
    return Tools::Convert2FixString(lineData[0][index], toFix);
}

int KDJ::getDataLength() const
{
    return hasData() ? (int)lineData[0].size() :0;
}

bool KDJ::hasData() const
{
    return (lineData.size() > 0 && lineData[0].size() > 0);
}

bool KDJ::hasData(int index) const
{
    
    if (hasData())
    {
        int count = (int)lineData[0].size();
        return 0 <= index && index < count;
    }
    else{
        return false;
    }
}

std::pair<double, double> KDJ::getAdjustedDataMinMax(int startIndex, int endIndex, const Rectangle & rect) const
{
    std::pair<double, double> ret = getLineDataMinMax(startIndex, endIndex);
    ret.first =  MIN(0, ret.first);
    ret.second =  MAX(100, ret.second);
    return ret;
}

std::vector<std::pair<std::string, std::string> > KDJ::getTopSideText(int index) const
{
    return Quotation::getTopSideText(lineData, index);
}

std::vector<std::pair<double, std::string> > KDJ::getLeftSideText(int startIndex, int endIndex, const Rectangle & rect, const Style & style) const
{
    string stcolor = style.sideTextColor;
    vector<pair<double, string> > result;
    result.push_back(make_pair(20, stcolor));
    result.push_back(make_pair(50, stcolor));
    result.push_back(make_pair(80, stcolor));
    return result;
}
